#pragma once 

#include "Containers/String.h"
#include "Containers/Map.h"

#include <chrono>
#include <thread>
#include <stack>
#include <semaphore>

class WHENGINE_API CCPUTimeCounter
{
public:
    static CCPUTimeCounter* Get();

    struct SCodeBlockTime
    {
        CString FieldName; // 代码块名称
        uint64_t Count;  // 调用次数
        float TotalTime; // 总运行时间,单位ms
        
        
        //下一级的代码块
        TMap<CString, std::shared_ptr<SCodeBlockTime>> Children;

        //临时变量，代码块开始时间
        std::chrono::time_point<std::chrono::steady_clock> StartTicks;
    };

    struct SThreadTime
    {
        std::thread::id ThreadID;

        //每帧统计结果
        TVector< std::shared_ptr<SCodeBlockTime>> Frames;

        //临时变量，当前线程的代码块栈
        std::stack< std::shared_ptr<SCodeBlockTime>> CodeBlockStack;
    };

    enum class ETimeCountThread
    {
        LogicThread=0,    //逻辑线程
        PreRenderThread,//预渲染线程
        RenderThread,   //渲染线程
    
        Max
    };

    struct STimeCountResult
    {
        SThreadTime ThreadTimes[uint64_t(ETimeCountThread::Max)];
    };

    enum class EState
    {
        Idle,
        TimeCounting,
        Finishing, // 结束中,等待所有线程结束
    };

    void BeginTimeCount();
    STimeCountResult EndTimeCount();
    EState GetState() const;

    static void PrintTimeCountResult(
        const STimeCountResult& InTimeCountResult
        ,int64_t MaxFrameCount=-1 //最大打印帧数,-1表示全部打印
    );

    void BeginFrameTimeCount(ETimeCountThread Thread);
    void EndFrameTimeCount(ETimeCountThread Thread);

    void BeginCodeBlockTimeCount(const CString& InFieldName);
    void EndCodeBlockTimeCount();

protected:

    std::atomic<EState> State= EState::Idle;

    //std::atomic<bool> bTimeCounting;
    //非逻辑线程使用的信号量
    std::counting_semaphore<((uint64_t)ETimeCountThread::Max-1)> Semaphore{0};
    STimeCountResult TimeCountResult;

    static CString GetThreadName(ETimeCountThread Thread);

    static void PrintCodeBlockTime(std::shared_ptr<SCodeBlockTime> InCodeBlockTime, int32_t Level);

};


#define BEGIN_FRAME_TIME_COUNT(Thread) CCPUTimeCounter::Get()->BeginFrameTimeCount(CCPUTimeCounter::ETimeCountThread::Thread);
#define END_FRAME_TIME_COUNT(Thread) CCPUTimeCounter::Get()->EndFrameTimeCount(CCPUTimeCounter::ETimeCountThread::Thread);

#define BEGIN_CODE_BLOCK_TIME_COUNT(FieldName) CCPUTimeCounter::Get()->BeginCodeBlockTimeCount(FieldName);
#define END_CODE_BLOCK_TIME_COUNT() CCPUTimeCounter::Get()->EndCodeBlockTimeCount();

struct CCPUTimeCounterScope
{
    CCPUTimeCounterScope(const CString& InFieldName)
    {
        FieldName = InFieldName;
        CCPUTimeCounter::Get()->BeginCodeBlockTimeCount(FieldName);
    }

    ~CCPUTimeCounterScope()
    {
        CCPUTimeCounter::Get()->EndCodeBlockTimeCount();
    }

    CString FieldName;
};

//代码块时间统计,使用"BLOCK_TIME_COUNT_行号"作为代码块变量名
#define CONCAT2IMPL(A,B) A##B
#define CONCAT2(A,B) CONCAT2IMPL(A,B)
#define CODE_BLOCK_TIME_COUNT(FieldName) CCPUTimeCounterScope  CONCAT2(BLOCK_TIME_COUNT ,__LINE__)     (FieldName);
